<!DOCTYPE html>
<html>
<head>
    <title>Three.js game</title>
	<script src="js/three.min.js"></script>
	<script src="js/RequestAnimationFrame.js"></script>
    <script src="js/Detector.js"></script>
	<script>
	var renderer, scene, camera, cube;
    
    var spriteH;
    var spritesEnemies = [];
    var containerWidth, containerHeight;
    var offset = 1135;
    var standingTexture, standingMirrorTexture;
    var hitTexture, hitMirrorTexture;
    var fadeSprite;
    var explosion;
    var texturesWalkForward = [];
    var texturesWalkBackward = [];
    var walkStateForward, walkStateBackward;
    var enemyMaterial;
    var turn;  // 1 = right; 2 = left
    var inHit = false;
    var speed;
    var enemySpeed;
    var hitRange;
    var dangerRange;
    var rate;
    var destroyed = false;
    var gameOver = false;
    var punchSound, fadeSound, explosionSound, levelUpSound;
    var score, exp, level; 
            
	function init()
	{
        var container = document.getElementById("gameContainer");
        if (!Detector.webgl){
            var p = document.getElementById("controls");
            p.style.display = "none";
            container.style.height = "100px";
            Detector.addGetWebGLMessage( { parent : container } );
            return;
        }
        containerWidth = container.offsetWidth;
        containerHeight = container.offsetHeight;
        renderer = new THREE.WebGLRenderer();
        renderer.setSize( containerWidth, containerHeight );
        
        container.appendChild( renderer.domElement );

        camera = new THREE.OrthographicCamera( 0, containerWidth, containerHeight, 0, 1, 10 );
        camera.position.z = 10;
        camera.position.x = -offset;
        scene = new THREE.Scene();
        initSprites();
        
        initGameParameters();
        document.getElementById('info').innerHTML = getInfo();
        document.onkeydown = handleKeyDown;
        
        initSounds();
        
        
        // Start
        animate();
	}
    
    function getInfo(){
        return  '<b>Score: </b>' + score + '<b> Exp: </b>' + exp + '/' + level*10 + 
                '<b> Level: </b>' + level + '<span style="color:gray;">' + '{Speed: ' + speed + ' Rate: ' + rate + ' Enemy speed: ' + enemySpeed.toFixed(2) + '}</span>';
    }
    
    function initGameParameters(){
        speed = 10;
        enemySpeed = 1.5;
        hitRange = 65;
        dangerRange = 25;
        rate = 100;
        level = 1;
        score = 0;
        exp = 0;
    }
    
    function initSounds(){
        punchSound = document.createElement('audio');
        var sourcePunch = document.createElement('source');
        sourcePunch.src = 'sounds/punch.wav';
        punchSound.appendChild(sourcePunch);
        
        fadeSound = document.createElement('audio');
        var sourceFade = document.createElement('source');
        sourceFade.src = 'sounds/fade.wav';
        fadeSound.appendChild(sourceFade); 
        
        explosionSound = document.createElement('audio');
        var sourceExp = document.createElement('source');
        sourceExp.src = 'sounds/explosion.mp3';
        explosionSound.appendChild(sourceExp); 
        
        levelUpSound = document.createElement('audio');
        var sourceLevelUp = document.createElement('source');
        sourceLevelUp.src = 'sounds/levelUp.wav';
        levelUpSound.appendChild(sourceLevelUp); 
    }
    
    function initSprites(){
        standingTexture = THREE.ImageUtils.loadTexture( "textures/hero_standing.png");
        standingMirrorTexture = THREE.ImageUtils.loadTexture( "textures/hero_mirror_standing.png");
        var material = new THREE.SpriteMaterial( { map: standingTexture } );
        spriteH = new THREE.Sprite( material );
        spriteH.scale.set( 80, 80, 1 );
        scene.add( spriteH );
        spriteH.position.set( 80 - offset, 110, 2 ); 
        
        hitTexture = THREE.ImageUtils.loadTexture( "textures/hero_hit.png");
        hitMirrorTexture = THREE.ImageUtils.loadTexture( "textures/hero_mirror_hit.png");
        walkStateForward = 0;
        walkStateBackward = 0
        texturesWalkForward[0] = THREE.ImageUtils.loadTexture( "textures/hero_walk1.png" );
        texturesWalkForward[1] = THREE.ImageUtils.loadTexture( "textures/hero_walk2.png" );
        texturesWalkForward[2] = THREE.ImageUtils.loadTexture( "textures/hero_walk3.png" );
        texturesWalkForward[3] = THREE.ImageUtils.loadTexture( "textures/hero_walk4.png" );
        
        texturesWalkBackward[0] = THREE.ImageUtils.loadTexture( "textures/hero_mirror_walk1.png" );
        texturesWalkBackward[1] = THREE.ImageUtils.loadTexture( "textures/hero_mirror_walk2.png" );
        texturesWalkBackward[2] = THREE.ImageUtils.loadTexture( "textures/hero_mirror_walk3.png" );
        texturesWalkBackward[3] = THREE.ImageUtils.loadTexture( "textures/hero_mirror_walk4.png" );
        
        var enemyTexture = THREE.ImageUtils.loadTexture( "textures/enemy.png");
        enemyMaterial = new THREE.SpriteMaterial( { map: enemyTexture } );
        
        var fadeTexture = THREE.ImageUtils.loadTexture( "textures/fade.png");
        fadeSprite = new THREE.Sprite( new THREE.SpriteMaterial( { map: fadeTexture } ) );
        fadeSprite.scale.set( 50, 50, 1 );
        
        var backgroundTexture = THREE.ImageUtils.loadTexture( "textures/background.jpg" ); 
        var backgroundSprite = new THREE.Sprite( new THREE.SpriteMaterial( { map: backgroundTexture } ) );
        backgroundSprite.scale.set( 1024*3, 512, 1 );
        backgroundSprite.position.set( containerWidth/2, containerHeight/2, 1 );
        scene.add( backgroundSprite ); 
        
        var explosionTexture = new THREE.ImageUtils.loadTexture( 'textures/explosion.png' );
        explosion = new THREE.Sprite( new THREE.SpriteMaterial( { map: explosionTexture } ) );
        explosion.scale.set( 160, 160, 1 );
    }
    
    var enemyCounter = 0;
    
    function enemyGenerator(){
        if (enemyCounter >= rate){
            var sprite = new THREE.Sprite( enemyMaterial );
            sprite.scale.set( 50, 50, 1 );
            sprite.position.set( (Math.random() * offset * 2) - offset, 400, 3 );
            scene.add( sprite );
            spritesEnemies.push(sprite);
            enemyCounter = 0;
        }
        enemyCounter++;
        enemyAI();
    }
    
    function enemyAI(){
        
        for (var i = 0, len = spritesEnemies.length; i < len; i++){
            var enemy = spritesEnemies[i];
            
            if (enemy.position.x < spriteH.position.x - hitRange*3)
                enemy.position.x += enemySpeed;
            else if (enemy.position.x < spriteH.position.x - hitRange)
                enemy.position.x += enemySpeed/2;
            else if (enemy.position.x > spriteH.position.x + hitRange*3)
                enemy.position.x -= enemySpeed;
            else if (enemy.position.x > spriteH.position.x + hitRange)
                enemy.position.x -= enemySpeed/2;
            else{
                if (enemy.position.y < spriteH.position.y + hitRange/2){
                    if (inHit){
                        if (!destroyed){
                            if (((hitTurn == 1) && (enemy.position.x > spriteH.position.x)) 
                             || ((hitTurn == -1) && (enemy.position.x < spriteH.position.x)))
                            {
                                scene.remove(enemy);
                                fadeSprite.position.set(enemy.position.x, enemy.position.y, 5);
                                scene.add(fadeSprite);
                                var index = spritesEnemies.indexOf(enemy);
                                if (index > -1) {
                                    spritesEnemies.splice(index, 1);
                                }
                                setTimeout(function(){
                                    scene.remove(fadeSprite);
                                }, 1000);                                
                                destroyed = true;
                                fadeSound.play();
                                score += level;
                                exp++;
                                document.getElementById('info').innerHTML = getInfo();
                                break;
                            }
                        }
                    }
                
                    if (enemy.position.x < spriteH.position.x - dangerRange){
                        enemy.position.x += enemySpeed/4;
                    }
                    else if (enemy.position.x > spriteH.position.x + dangerRange)
                        enemy.position.x -= enemySpeed/4;
                    else{
                        explosion.position.set(spriteH.position.x, spriteH.position.y, 5);
                        scene.add( explosion );
                        explosionSound.play();
                        gameOver = true;
                    }
                }
            }
                
            if (enemy.position.y > spriteH.position.y)
                enemy.position.y -= 1;
        }
    }
    
    

    function animate()
	{
        if (!inHit)
            walking();
        if (inHit)
            hit();
        enemyGenerator();
        // Render
		renderer.render( scene, camera );
		// Ask for another frame
        
        if (exp == 10*level){
            levelUp();
        }
        
        if (!gameOver)
            requestAnimationFrame(animate);
        else{
            window.setTimeout(restart, 3000)
        }
	}
    
    function levelUp(){
        levelUpSound.play();
        if (speed > 5)
        speed -= 0.5;
        enemySpeed *= 1.1;
        if (rate > 50)
            rate -= 10;
        level++;
        exp = 0;
        document.getElementById('info').innerHTML = getInfo();
    }
    
    function restart(){
        scene.remove(explosion);
        for (var i = 0, len = spritesEnemies.length; i < len; i++){
            var enemy = spritesEnemies[i];
            scene.remove(enemy);
        }
        spritesEnemies = [];
        initGameParameters();
        camera.position.x = -offset;
        spriteH.position.set( 80 - offset, 110, 2 );
        gameOver = false; 
        document.getElementById('info').innerHTML = getInfo();
        requestAnimationFrame(animate);
    }
    
    var walkCounter = 0;
    
    function walking(){
        // Walk animation
        if (spriteH != undefined){
            if (turn == 1){
                spriteH.material.map = texturesWalkForward[walkStateForward]; 
                if (walkCounter > 25){
                    spriteH.material.map = standingTexture; 
                    walkStateBackward = 0;
                    walkStateForward = 0;
                    walkCounter = 0;
                    turn = 0;
                }
            }
            else if (turn == -1){
                spriteH.material.map = texturesWalkBackward[walkStateBackward];
                spriteH.material.map.needsUpdate = true;
                if (walkCounter > 25){
                    spriteH.material.map = standingMirrorTexture; 
                    walkStateBackward = 0;
                    walkStateForward = 0;
                    walkCounter = 0;
                    turn = 0;
                }
            }
        }
        walkCounter++;
    }
    
    var hitCounter = 0;
    var hitTurn;
    
	function hit(){
        if (hitCounter == 0){
            destroyed = false;
            if (turn == 1){
                spriteH.material.map = hitTexture;
                hitTurn = turn;
            }
            else if (turn == -1){
                spriteH.material.map = hitMirrorTexture;
                hitTurn = turn;
            }
            else if (spriteH.material.map == standingTexture){
                spriteH.material.map = hitTexture;
                hitTurn = 1;
            }
            else if (spriteH.material.map == standingMirrorTexture){
                spriteH.material.map = hitMirrorTexture;
                hitTurn = -1;
            }
        }
        else if(hitCounter > 10){
            inHit = false;
            hitCounter = -1;
            turn = hitTurn;
            walkStateBackward = 0;
            walkStateForward = 0;
            walkCounter = 26;
        }
        hitCounter++;
    }
    
    
    //Handle keys
    var KEYCODE_SPACE = 32;
    var KEYCODE_UP = 38;	
    var KEYCODE_LEFT = 37;
    var KEYCODE_RIGHT = 39;
    var KEYCODE_DOWN = 40;	
    var KEYCODE_W = 87;	
    var KEYCODE_A = 65;
    var KEYCODE_D = 68;
    var KEYCODE_S = 83;
    
    function handleKeyDown(e) {
        if(!e){ var e = window.event; }
        switch(e.keyCode) {
            case KEYCODE_A:
            case KEYCODE_LEFT:
                if (spriteH.position.x > -1110){ 
                    turn = -1;
                    walkStateBackward++;
                    if (walkStateBackward > 3)
                        walkStateBackward = 0; 
                    spriteH.position.x -= speed;
                }
                if (camera.position.x > -offset)
                    if ((spriteH.position.x - camera.position.x) <= 155)
                        camera.position.x -= speed;
                break;
            case KEYCODE_D:
            case KEYCODE_RIGHT: 
                if (spriteH.position.x < 1915){ 
                    walkStateForward++;
                    turn = 1;
                    if (walkStateForward > 3)
                        walkStateForward = 0; 
                    spriteH.position.x += speed;
                }
                if (camera.position.x < offset)
                    if ((spriteH.position.x - camera.position.x) >= 555)
                        camera.position.x += speed;
                break;
            case KEYCODE_W: 
            case KEYCODE_UP:
                //inJump = true;
                //spriteH.position.y += speed;
                break;
            case KEYCODE_S: 
            case KEYCODE_DOWN:
                //spriteH.position.y -= speed;
                break;
            case KEYCODE_SPACE:
                inHit = true;
                punchSound.play();
                break;
        }
    }
	</script>
</head>
<style>
#controls
{
   width:240px;
   font-size:12pt; 
   border-style:dotted; 
   border-width:1px;
   margin-top:30px;

   -webkit-animation-name:fade;
   -webkit-animation-delay: 20s;
   -webkit-animation-duration:3s;
   -webkit-animation-fill-mode: forwards;

   animation-name:fade;
   animation-delay: 20s;
   animation-duration:3s;
   animation-fill-mode: forwards;
}
@-webkit-keyframes fade
{
   from   {visible:hidden; opacity: 1;}
   to {visibility:hidden; opacity: 0;}
}
@keyframes fade
{
   from   {visible:hidden; opacity: 1;}
   to {visibility:hidden; opacity: 0;}
}

#gameContainer
{
   width:800px; 
   height:512px;
}
</style>
<body onLoad="init();">
    <div id="gameContainer"><label id="info"><label></div>
    <p id="controls">
        <b>Controls:</b>
        </br><i>Move left:</i> Hold A or left arrow
        </br><i>Move right:</i> Hold D or right arrow
        </br><i>Attack:</i> Space
    </p>
</body>
</html>
